-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathzad2.py
114 lines (89 loc) · 2.36 KB
/
zad2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
"""
ZŁOŻONOŚĆ
Obliczeniowa: O(N + M)
Pamięciowa: O(N + M)
"""
from zad2testy import runtests
def num_to_edge(n: int, M: '10^K') -> '(u, v)':
return divmod(n, M)
def build_graph(L, M, n):
G = [[] for _ in range(n)]
for num in L:
u, v = num_to_edge(num, M)
G[u].append(v)
return G
def get_max_vert_ind(L, M):
n = 0
for num in L:
n = max(n, max(num_to_edge(num, M)))
return n
def eulerian(G):
n = len(G)
out_deg = [0] * n
in_deg = [0] * n
for u in range(n):
for v in G[u]:
out_deg[u] += 1
in_deg[v] += 1
path_begin = path_end = -1
for i in range(n):
if out_deg[i] == in_deg[i]: continue
if out_deg[i] - in_deg[i] == 1:
if path_begin >= 0: break
path_begin = i
continue
if in_deg[i] - out_deg[i] == 1:
if path_end >= 0: break
path_end = i
continue
break
# If not broken, there might be a path or a cycle
else:
# Only begin or only end
if path_end * path_begin < 0:
return None, []
# Cycle
elif path_begin == path_end == -1:
return None, out_deg # In a cycle we can start no matter where, hence return None
# Path
else:
return path_begin, out_deg
# Otherwise, nothing
return -1, []
def euler(G):
"""
Return a cycle if there is a cycle or a path if only a path exists.
If there is neither cycle nor path return an empty result.
"""
begin, out = eulerian(G)
# If no cycle nor path
if not out: return []
# If there is a cycle, choose the first vertex which has neighbours
# as the beginning vertex
if begin is None:
for i in range(len(G)):
if G[i]:
begin = i
break
result = []
def dfs(u):
while out[u]:
out[u] -= 1
v = G[u][out[u]]
dfs(v)
result.append(u)
dfs(begin)
return result[::-1]
def get_result(vert, M):
n = len(vert)
L = [0] * (n - 1)
for i in range(n - 1):
L[i] = vert[i] * M + vert[i + 1]
return L
def order(L, K):
M = 10 ** K
n = get_max_vert_ind(L, M) + 1
G = build_graph(L, M, n)
vert = euler(G)
return get_result(vert, M) if vert else None
runtests(order)